package com.rs.game.player.skills;

import com.rs.cache.loaders.ItemDefinitions;
import com.rs.game.Animation;
import com.rs.game.Entity;
import com.rs.game.Graphics;
import com.rs.game.Hit;
import com.rs.game.World;
import com.rs.game.WorldTile;
import com.rs.game.Hit.HitLook;
import com.rs.game.item.Item;
import com.rs.game.npc.NPC;
import com.rs.game.player.CombatDefinitions;
import com.rs.game.player.Player;
import com.rs.game.player.Skills;
import com.rs.game.player.content.Magic;
import com.rs.game.tasks.WorldTask;
import com.rs.game.tasks.WorldTasksManager;
import com.rs.utils.Utils;

public class PlayerCombat extends Skill {

	private Entity target;
	private int max_hit; //temporary constant
	private double base_mage_xp; //temporary constant
	private int mage_hit_gfx; //temporary constant
	public PlayerCombat(Entity target) {
		this.target = target;
	}
	
	@Override
	public boolean start(Player player) {
		player.setNextFaceEntity(target);
		if(checkAll(player)) {
			addAttackedByDelay(player);
			return true;
		}
		return false;
	}

	@Override
	public boolean process(Player player) {
		return checkAll(player);
	}

	@Override
	public int processWithDelay(Player player) {
		if(player.getFreezeDelay() >= System.currentTimeMillis())
			return 0;
		int isRanging = isRanging(player);
		int spellId = player.getCombatDefinitions().getSpellId();
		int maxDistance = isRanging != 0 || spellId > 0 ? 7 : 0;
		int distanceX = player.getX()-target.getX();
		int distanceY = player.getY()-target.getY();
		int size = target.getSize();
		if(player.hasWalkSteps())
			maxDistance += 1;
		if(distanceX > size+maxDistance || distanceX < -1-maxDistance || distanceY > size+maxDistance || distanceY < -1-maxDistance)
			return 0;
		if(spellId > 0) {
			boolean manualCast = spellId >= 256;
			return mageAttack(player, manualCast ? spellId-256 : spellId, !manualCast);
		}else {
			if(isRanging == 0)
				return meleeAttack(player);
			else if (isRanging == 1) {
				player.getPackets().sendGameMessage("This ammo is not very effective with this weapon.");
				return -1;
			}else if (isRanging == 3) {
				player.getPackets().sendGameMessage("You dont have any ammo in your backpack.");
				return -1;
			}else
				return rangeAttack(player);
		}
	}
	
	
	private int getRangeCombatDelay(int weaponId, int attackStyle) {
		int delay = 0;
		
		switch(weaponId) {
		case 15241:
			delay = 7;
			break;
	     case 11235: //dark bows
	     case 15701:
	     case 15702:
	     case 15703:
	     case 15704:
	    	 delay = 9;
	    	 break;
		default:
			delay = 6;
		break;
		}
		
		if(attackStyle == 1)
			delay--;
		else if (attackStyle == 2)
			delay++;
		return delay;
	}
	
	
	public int mageAttack(Player player, int spellId, boolean autocast) {
		if(!autocast) {
			player.getCombatDefinitions().resetSpells(false);
			player.getSkillExecutor().forceStop();
		}
		if(!Magic.checkCombatSpell(player, spellId, -1, true)) {
			if(autocast)
				player.getCombatDefinitions().resetSpells(true);
			return -1; //stops 
		}
		switch(spellId) {
		case 25: //air strike
			player.setNextAnimation(new Animation(14221));
			mage_hit_gfx = 2700;
			base_mage_xp = 5.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 20))));
			World.sendProjectile(player, target, 2699, 18, 18, 50, 50, 0, 0);
			return 5;
		case 28: //water strike
			player.setNextGraphics(new Graphics(2701));
			player.setNextAnimation(new Animation(14221));
			mage_hit_gfx = 2708;
			base_mage_xp = 7.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 40))));
			World.sendProjectile(player, target, 2703, 18, 18, 50, 50, 0, 0);
			return 5;
		case 30: //earth strike
			player.setNextGraphics(new Graphics(2713));
			player.setNextAnimation(new Animation(14221));
			mage_hit_gfx = 2723;
			base_mage_xp = 9.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 60))));
			World.sendProjectile(player, target, 2718, 18, 18, 50, 50, 0, 0);
			return 5;
		case 32: //fire strike
			player.setNextGraphics(new Graphics(2728));
			player.setNextAnimation(new Animation(14221));
			mage_hit_gfx = 2737;
			base_mage_xp = 11.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 80))));
			World.sendProjectile(player, target, 2729, 18, 18, 50, 50, 0, 0);
			return 5;
		case 34: //air bolt
			player.setNextAnimation(new Animation(14220));
			mage_hit_gfx = 2700;
			base_mage_xp = 13.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 90))));
			World.sendProjectile(player, target, 2699, 18, 18, 50, 50, 0, 0);
			return 5;
		case 39: //water bolt
			player.setNextGraphics(new Graphics(2707, 0, 100));
			player.setNextAnimation(new Animation(14220));
			mage_hit_gfx = 2709;
			base_mage_xp = 16.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 100))));
			World.sendProjectile(player, target, 2704, 18, 18, 50, 50, 0, 0);
			return 5;
		case 42: //earth bolt
			player.setNextGraphics(new Graphics(2714));
			player.setNextAnimation(new Animation(14222));
			mage_hit_gfx = 2724;
			base_mage_xp = 19.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 110))));
			World.sendProjectile(player, target, 2719, 18, 18, 50, 50, 0, 0);
			return 5;
		case 45: //fire bolt
			player.setNextGraphics(new Graphics(2728));
			player.setNextAnimation(new Animation(14223));
			mage_hit_gfx = 2738;
			base_mage_xp = 22.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 120))));
			World.sendProjectile(player, target, 2731, 18, 18, 50, 50, 0, 0);
			return 5;
		case 49: //air blast
			player.setNextAnimation(new Animation(14221));
			mage_hit_gfx = 2700;
			base_mage_xp = 25.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 130))));
			World.sendProjectile(player, target, 2699, 18, 18, 50, 50, 0, 0);
			return 5;
		case 52: //water blast
			player.setNextGraphics(new Graphics(2701));
			player.setNextAnimation(new Animation(14220));
			mage_hit_gfx = 2710;
			base_mage_xp = 31.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 150))));
			World.sendProjectile(player, target, 2705, 18, 18, 50, 50, 0, 0);
			return 5;
		case 58: //earth blast
			player.setNextGraphics(new Graphics(2715));
			player.setNextAnimation(new Animation(14222));
			mage_hit_gfx = 2725;
			base_mage_xp = 31.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 160))));
			World.sendProjectile(player, target, 2720, 18, 18, 50, 50, 0, 0);
			return 5;
		case 63: //fire blast
			player.setNextGraphics(new Graphics(2728));
			player.setNextAnimation(new Animation(14223));
			mage_hit_gfx = 2739;
			base_mage_xp = 34.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 120))));
			World.sendProjectile(player, target, 2733, 18, 18, 50, 50, 0, 0);
			return 5;
		case 70: //air wave
			player.setNextAnimation(new Animation(14221));
			mage_hit_gfx = 2700;
			base_mage_xp = 36;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 170))));
			World.sendProjectile(player, target, 2699, 18, 18, 50, 50, 0, 0);
			return 5;
		case 73: //water wave
			player.setNextGraphics(new Graphics(2702));
			player.setNextAnimation(new Animation(14220));
			mage_hit_gfx = 2710;
			base_mage_xp = 37.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 180))));
			World.sendProjectile(player, target, 2706, 18, 18, 50, 50, 0, 0);
			return 5;
		case 77: //earth wave
			player.setNextGraphics(new Graphics(2716));
			player.setNextAnimation(new Animation(14222));
			mage_hit_gfx = 2726;
			base_mage_xp = 42.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 190))));
			World.sendProjectile(player, target, 2721, 18, 18, 50, 50, 0, 0);
			return 5;
		case 80: //fire wave
			player.setNextGraphics(new Graphics(2728));
			player.setNextAnimation(new Animation(14223));
			mage_hit_gfx = 2740;
			base_mage_xp = 22.5;
			delayMagicHit(2, getMagicHit(player, Utils.getRandom(getMagicMaxHit(player, 200))));
			World.sendProjectile(player, target, 2735, 18, 18, 50, 50, 0, 0);
			return 5;
		}
		
		return -1; //stops atm
	}
	
	public int getMagicMaxHit(final Player player, int baseDamage) {
		
		double att = player.getSkills().getLevel(Skills.MAGIC)
			    + player.getCombatDefinitions().getBonuses()
			    [CombatDefinitions.MAGIC_ATTACK];
	att *= player.getPrayer().getMageMultiplier();
	double def;
	if(target instanceof Player) {
		Player p2 = (Player) target;
		 def = p2.getSkills().getLevel(Skills.DEFENCE)
					+  p2.getCombatDefinitions().getBonuses()
					 [ CombatDefinitions.MAGIC_DEF];
					def *= p2.getPrayer().getDefenceMultiplier();
	 }else{
		 NPC n = (NPC) target;
		 def = n.getBonuses() == null ? 0 : n.getBonuses()[CombatDefinitions.MAGIC_DEF];
	 }
    double prob = att / def;
    if (prob > 0.90) //max, 90% prob hit so even lvl 138 can miss at lvl 3
	prob = 0.90;
    else if (prob < 0.05) //minimun 5% so even lvl 3 can hit lvl 138
	prob = 0.05;
    if(prob < Math.random())
	return 0;
		
		max_hit = (int) (baseDamage * (1.0 + player.getCombatDefinitions().getBonuses()[CombatDefinitions.MAGIC_DAMAGE]));
		max_hit *= player.getPrayer().getMageMultiplier();
		return max_hit;
	}
	
	private int rangeAttack(final Player player) {
		final int weaponId = player.getEquipment().getWeaponId();
		int attackStyle = player.getCombatDefinitions().getAttackStyle();
		int combatDelay = getRangeCombatDelay(weaponId, attackStyle);
		if(player.getCombatDefinitions().isUsingSpecialAttack()) {
			int specAmt = getSpecialAmmount(weaponId);
			if(specAmt == 0) {
				 player.getPackets().sendGameMessage("This weapon has no special Attack, if you still see special bar please relogin.");
				 player.getCombatDefinitions().desecreaseSpecialAttack(0);
				 return combatDelay;
			}
		    if(player.getCombatDefinitions().getSpecialAttackPercentage() < specAmt) {
				 player.getPackets().sendGameMessage("You don't have enough power left.");
				 player.getCombatDefinitions().desecreaseSpecialAttack(0);
				 return combatDelay;
			}
		    player.getCombatDefinitions().desecreaseSpecialAttack(specAmt);
		    switch(weaponId) {
			case 859: //magic longbow
			case 861: //magic shortbow
			case 10284: //Magic composite bow
			case 18332: //Magic longbow (sighted)
				 player.setNextAnimation(new Animation(1074));
	    		 player.setNextGraphics(new Graphics(249, 0, 100));
	    		 World.sendProjectile(player, target, 249, 41, 16, 41, 35, 16, 0);
	    		 World.sendProjectile(player, target, 249, 41, 16, 35, 35, 21, 0);
	    		 delayHit(1, weaponId, attackStyle, getRangeHit(player, getRandomMaxHit(player, weaponId, attackStyle, true, true, 1.0, true)));
	    		 delayHit(2, weaponId, attackStyle, getRangeHit(player, getRandomMaxHit(player, weaponId, attackStyle, true, true, 1.0, true)));
	    		 dropAmmo(player, 2);
	    	break;
		    case 11235: //dark bows
		    case 15701:
		    case 15702:
		    case 15703:
		    case 15704:
		    	 int ammoId = player.getEquipment().getAmmoId();
	    		 player.setNextAnimation(new Animation(getWeaponAttackEmote(weaponId, attackStyle)));
	    		 player.setNextGraphics(new Graphics(getArrowThrowGfxId(weaponId, ammoId), 0, 100));
		    	 if(ammoId == 11212) {
		    		 int damage = getRandomMaxHit(player, weaponId, attackStyle, true, true, 1.5, true);
		    		 if(damage < 80)
		    			 damage = 80;
		    		 int damage2 = getRandomMaxHit(player, weaponId, attackStyle, true, true, 1.5, true);
		    		 if(damage2 < 80)
		    			 damage2 = 80;
		    		 World.sendProjectile(player, target, 1099, 41, 16, 41, 35, 16, 0);
		    		 World.sendProjectile(player, target, 1099, 41, 16, 35, 35, 21, 0);
		    		 delayHit(1, weaponId, attackStyle, getRangeHit(player, damage));
		    		 delayHit(2, weaponId, attackStyle, getRangeHit(player, damage2));
		    		 WorldTasksManager.schedule(new WorldTask() {
						@Override
						public void run() {
							target.setNextGraphics(new Graphics(1100, 0, 100));
						}
		    		 }, 2);
		    	 }else{
		    		 int damage = getRandomMaxHit(player, weaponId, attackStyle, true, true, 1.3, true);
		    		 if(damage < 50)
		    			 damage = 50;
		    		 int damage2 = getRandomMaxHit(player, weaponId, attackStyle, true, true, 1.3, true);
		    		 if(damage2 < 50)
		    			 damage2 = 50;
		    		 World.sendProjectile(player, target, 1101, 41, 16, 41, 35, 16, 0);
		    		 World.sendProjectile(player, target, 1101, 41, 16, 35, 35, 21, 0);
		    		 delayHit(1, weaponId, attackStyle, getRangeHit(player, damage));
		    		 delayHit(2, weaponId, attackStyle, getRangeHit(player, damage2));
		    	 }
		    	 dropAmmo(player, 2);

		    	 break;
		    case 14684: //zanik cbow
		    	player.setNextAnimation(new Animation(getWeaponAttackEmote(weaponId, attackStyle)));
		    	player.setNextGraphics(new Graphics(1714));
		    	World.sendProjectile(player, target, 2001, 41, 41, 41, 35, 0, 0);
		    	delayHit(2, weaponId, attackStyle, getRangeHit(player, getRandomMaxHit(player, weaponId, attackStyle, true, true, 1.0, true)+30+Utils.getRandom(120)));
		    	dropAmmo(player);
		   	break;
		    default:
		    player.getPackets().sendGameMessage("This weapon has no special Attack, if you still see special bar please relogin.");
			return combatDelay;
		    }
			return combatDelay;
		}else {
		    if(weaponId != -1) {
		    	String weaponName = ItemDefinitions.getItemDefinitions(weaponId).getName();
			     if(weaponName.contains("throwing axe") || weaponName.contains("knife") || weaponName.contains("dart") || weaponName.contains("javelin") || weaponName.contains("thrownaxe")) {
			    	 player.setNextGraphics(new Graphics(getKnifeThrowGfxId(weaponId), 0, 100));
			    	 World.sendProjectile(player, target, getKnifeThrowGfxId(weaponId), 41, 16, 60, 30, 16, 0);
			    	 delayHit(1, weaponId, attackStyle, getRangeHit(player, getRandomMaxHit(player, weaponId, attackStyle, true)));
			    	 dropAmmo(player, -1);
			     }else if(weaponName.contains("crossbow")) {
			    	 int damage = getRandomMaxHit(player, weaponId, attackStyle, true);
			    	 int ammoId = player.getEquipment().getAmmoId();
			    	 if(ammoId != -1 && Utils.getRandom(10) == 5) {
			    		 switch(ammoId) {
			    		 case 9237:
			    			 target.setNextGraphics(new Graphics(755));
			    			 if(target instanceof Player) {
			    				 Player p2 = (Player) target;
			    				 p2.stopAll();
			    			 }else {
			    				 @SuppressWarnings("unused")
								NPC n = (NPC) target;
			    				 //TODO stop attack
			    			 }
			    			 break;
			    		 case 9242:
			    			 max_hit = Short.MAX_VALUE;
			    			 damage = (int) (target.getHitpoints()*0.2);
			    			 target.setNextGraphics(new Graphics(754));
			    			 player.applyHit(new Hit(target, player.getHitpoints() > 20 ? (int) (player.getHitpoints() * 0.1) : 1, HitLook.Reflect_Hit));
			    			 break;
			    		 case 9244:
			    			 target.setNextGraphics(new Graphics(756));
			    			 damage += Utils.getRandom(hasAntiDragProtection() ? 100 : 250);
			    			 break;
			    		 case 9245:
			    			 target.setNextGraphics(new Graphics(753));
			    			 damage += Utils.getRandom(150);
			    			 player.heal((int) (player.getMaxHitpoints() * 0.25));
			    			 break;
			    		 }
			    	 }
			    	 delayHit(2, weaponId, attackStyle, getRangeHit(player, damage));
			    	 dropAmmo(player);
			     }else if (weaponId == 15241) {//handcannon
			    	 if(Utils.getRandom(player.getSkills().getLevel(Skills.FIREMAKING)) == 0) {
			    		 player.setNextGraphics(new Graphics(2140)); 
			    		 player.getEquipment().getItems().set(3, null);
			    		 player.getEquipment().refresh(3);
			    		 player.getAppearence().generateAppearenceData();
			    		 player.applyHit(new Hit(player, Utils.getRandom(150)+10, HitLook.Hit));
			    		 player.setNextAnimation(new Animation(12175));
			    		 return combatDelay;
			    	 }else {
			    		 player.setNextGraphics(new Graphics(2138)); 
			    		 World.sendProjectile(player, target, 2143, 18, 18, 60, 30, 0, 0);
			    		 delayHit(1, weaponId, attackStyle, getRangeHit(player, getRandomMaxHit(player, weaponId, attackStyle, true)));
			    		 dropAmmo(player, -2);
			    	 }
			     }else { //bow/default
			    	 final int ammoId = player.getEquipment().getAmmoId();
			    	 player.setNextGraphics(new Graphics(getArrowThrowGfxId(weaponId, ammoId), 0, 100));
			    	 World.sendProjectile(player, target, getArrowProjectileGfxId(weaponId, ammoId), 41, 16, 41, 35, 16, 0);
			    	 delayHit(1, weaponId, attackStyle, getRangeHit(player, getRandomMaxHit(player, weaponId, attackStyle, true)));
			    	 if(weaponId == 11235 || weaponId == 15701|| weaponId == 15702
			    			 || weaponId == 15703  || weaponId == 15704) { //dbows
			    		 World.sendProjectile(player, target, getArrowProjectileGfxId(weaponId, ammoId), 41, 16, 35, 35, 21, 0);
			    		 delayHit(2, weaponId, attackStyle, getRangeHit(player, getRandomMaxHit(player, weaponId, attackStyle, true)));
						 dropAmmo(player, 2);
			    	 }else
			    		 dropAmmo(player);
			     }
				player.setNextAnimation(new Animation(getWeaponAttackEmote(weaponId, attackStyle)));
		    }
		}
		return combatDelay;
	}
	
	public void dropAmmo(Player player, int quantity) {
		if(quantity == -2) {
			 final int ammoId = player.getEquipment().getAmmoId();
			player.getEquipment().removeAmmo(ammoId, 1);
		}else if(quantity == -1) {
			 final int weaponId = player.getEquipment().getAmmoId();
			 if(weaponId != -1) {
				if(Utils.getRandom(3) > 0) {
					int capeId = player.getEquipment().getCapeId();
					if(capeId != -1 && ItemDefinitions.getItemDefinitions(capeId).getName().contains("Ava's"))
							return; //nothing happens
				}else {
					player.getEquipment().removeAmmo(weaponId, quantity);
					return;
				}
				player.getEquipment().removeAmmo(weaponId, quantity);
				 World.updateGroundItem(new Item(weaponId, quantity), new WorldTile(target.getCoordFaceX(target.getSize()), target.getCoordFaceY(target.getSize()), target.getPlane()), player);
			 }
		}else{
			 final int ammoId = player.getEquipment().getAmmoId();
			 if(Utils.getRandom(3) > 0) {
					int capeId = player.getEquipment().getCapeId();
					if(capeId != -1 && ItemDefinitions.getItemDefinitions(capeId).getName().contains("Ava's"))
							return; //nothing happens
				}else {
					player.getEquipment().removeAmmo(ammoId, quantity);
					return;
				}
			 if(ammoId != -1) {
				 player.getEquipment().removeAmmo(ammoId, quantity);
				 World.updateGroundItem(new Item(ammoId, quantity), new WorldTile(target.getCoordFaceX(target.getSize()), target.getCoordFaceY(target.getSize()), target.getPlane()), player);
			 }
		}
	}
	
	public void dropAmmo(Player player) {
		dropAmmo(player, 1);
	}
	
	  public int getArrowThrowGfxId(int weaponId, int arrowId) {
			if (arrowId == 884) {
			    return 18;
			} else if (arrowId == 886) {
			    return 20;
			} else if (arrowId == 888) {
			    return 21;
			} else if (arrowId == 890) {
			    return 22;
			} else if (arrowId == 892)
			    return 24;
			return 19; //bronze default
		    }
		    
	 public int getArrowProjectileGfxId(int weaponId, int arrowId) {
			if (arrowId == 884) {
			    return 11;
			} else if (arrowId == 886) {
			    return 12;
			} else if (arrowId == 888) {
			    return 13;
			} else if (arrowId == 890) {
			    return 14;
			} else if (arrowId == 892) 
			    return 15;
		    	else if (arrowId == 11212)
			    return 1120;
			 return 10;//bronze default
	  }
	
	public boolean hasAntiDragProtection() {
		if(target instanceof NPC)
			return false;
		Player p2 = (Player) target;
		int shieldId = p2.getEquipment().getShieldId();
		return shieldId == 1540 || shieldId == 11283;
	}
	
	
    public int getKnifeProjectileGfxId(int weaponId) {
	return -1; //TODO
    }
	
	
    public int getKnifeThrowGfxId(int weaponId) {
	//knives TODO ALL
	if (weaponId == 868) {
	    return 225;
	} else if (weaponId == 867) {
	    return 224;
	} else if (weaponId == 866) {
	    return 223;
	} else if (weaponId == 865) {
	    return 221;
	} else if (weaponId == 864) {
	    return 219;
	} else if (weaponId == 863) {
	    return 220;
	}
	
	//darts
	if (weaponId == 806) {
	    return 232;
	} else if (weaponId == 807) {
	    return 233;
	} else if (weaponId == 808) {
	    return 234;
	} else if (weaponId == 3093) {
	    return 273;
	} else if (weaponId == 809) {
	    return 235;
	} else if (weaponId == 810) {
	    return 236;
	} else if (weaponId == 811) {
	    return 237;
	} else if (weaponId == 11230) {
	    return 1123; 
	}
	
	return 219;
    }
	
	@SuppressWarnings("unused")
	private int getRangeHitDelay(Player player) {
		return Utils.getDistance(player.getX(), player.getY(), target.getX(), target.getY()) >= 5 ? 2 : 1;
	}
	
	private int meleeAttack(Player player) {
		int weaponId = player.getEquipment().getWeaponId();
		int attackStyle = player.getCombatDefinitions().getAttackStyle();
		int combatDelay = getMeleeCombatDelay(weaponId);
		if(player.getCombatDefinitions().isUsingSpecialAttack()) {
			player.getCombatDefinitions().switchUsingSpecialAttack();
			int specAmt = getSpecialAmmount(weaponId);
			if(specAmt == 0) {
				 player.getPackets().sendGameMessage("This weapon has no special Attack, if you still see special bar please relogin.");
				 player.getCombatDefinitions().desecreaseSpecialAttack(0);
				 return combatDelay;
			}
		    if(player.getCombatDefinitions().getSpecialAttackPercentage() < specAmt) {
				 player.getPackets().sendGameMessage("You don't have enough power left.");
				 player.getCombatDefinitions().desecreaseSpecialAttack(0);
				 return combatDelay;
			}
		    player.getCombatDefinitions().desecreaseSpecialAttack(specAmt);
		    switch(weaponId) {
		     case 15442:// whip start
		     case 15443:
		     case 15444:
		     case 15441:
		     case 4151: 
		    		player.setNextAnimation(new Animation(11971));
		    		target.setNextGraphics(new Graphics(2108,0,100));
		    		if(target instanceof Player) {
		    			Player p2 = (Player) target;
		    			p2.setRunEnergy(p2.getRunEnergy() > 25 ? p2.getRunEnergy()-25 : 0);
		    		}
		    		delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true)));
		    break;
		    case 11730: //sara sword
		    	player.setNextAnimation(new Animation(11993));
		    	target.setNextGraphics(new Graphics(1194));
		    	delayNormalHit(weaponId, attackStyle, getMeleeHit(player, 50+Utils.getRandom(100)), getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true)));
		    break;
		    case 11698: //sgs
		    	//player.setNextAnimation(new Animation(-1)); //TODO
		    	player.setNextGraphics(new Graphics(2109));
				 int sgsdamage = getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.1, true);
				 player.heal(sgsdamage/2);
				 player.getSkills().restorePrayer(sgsdamage/4);
				 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, sgsdamage));
			break;
		    case 11696: //bgs
		    	//player.setNextAnimation(new Animation(-1)); //TODO
		    	player.setNextGraphics(new Graphics(2109));
		    	delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.1, true)));
		    	break;	
		    case 11694: //ags
		    	player.setNextAnimation(new Animation(11989));
		    	player.setNextGraphics(new Graphics(2113));
		    	delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.5, true)));
		    	break;	
		    case 13899: //vls
		    	player.setNextAnimation(new Animation(10502));
		    	delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.20, true)));
		    	break;	
		    case 13902: //statius hammer
		    	player.setNextAnimation(new Animation(10505));
		    	player.setNextGraphics(new Graphics(1840));
		    	delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.30, true)));
		    	break;	
		    case 13905: //vesta spear
		    	player.setNextAnimation(new Animation(10499));
		    	player.setNextGraphics(new Graphics(1835));
		    	delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.10, true)));
		    	break;	
		    case 19784: //korasi sword
		    	player.setNextAnimation(new Animation(14788));
		    	player.setNextGraphics(new Graphics(1729));
		    	int korasiDamage = 0;
		    	if(target instanceof Player) {
		    		Player p2 = (Player) target;
		    		korasiDamage = getMaxHit(p2, p2.getEquipment().getWeaponId(), p2.getCombatDefinitions().getAttackStyle(), false, false, 1.0);
		    	} else {
		    		NPC n = (NPC) target;
		    		korasiDamage = n.getMaxHit();
		    	}
		    	double multiplier = 0.5;
				multiplier += Math.random();
				max_hit = korasiDamage;
				korasiDamage *= multiplier;
				delayNormalHit(weaponId, attackStyle, getMagicHit(player, korasiDamage));
				break;
		    case 11700:
		    	 int zgsdamage = getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true);
		    	 player.setNextAnimation(new Animation(7070));
			     player.setNextGraphics(new Graphics(1221));
		    	 if(zgsdamage != 0 && target.getSize() <= 1) { //freezes small npcs
		    		 target.setNextGraphics(new Graphics(2104));
		    		 target.addFreezeDelay(18000); //18seconds
		    	 }
		    	 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, zgsdamage));
		    	break;
		    case 14484: //d claws
		    	player.setNextAnimation(new Animation(10961));
			    player.setNextGraphics(new Graphics(1950));
			    int hit1 = getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true);
				 int hit2 = hit1 == 0 ? getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true) : hit1;
					if(hit1 == 0 && hit2 == 0) {
						int hit3 = getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true);
						if(hit3 == 0) {
							int hit4 = getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true);
							if(hit4 == 0) {
								delayNormalHit(weaponId, attackStyle, getMeleeHit(player, hit2), getMeleeHit(player, hit1));
								delayHit(1, weaponId, attackStyle, getMeleeHit(player, 1), getMeleeHit(player, hit3));
							}else{
								delayNormalHit(weaponId, attackStyle, getMeleeHit(player, hit2), getMeleeHit(player, hit1));
								delayHit(1, weaponId, attackStyle, getMeleeHit(player, (int) (hit4*1.5)), getMeleeHit(player, hit3));
							}
						}else{
							delayNormalHit(weaponId, attackStyle, getMeleeHit(player, hit2), getMeleeHit(player, hit1));
							delayHit(1, weaponId, attackStyle, getMeleeHit(player, hit3), getMeleeHit(player, hit3));
						}
					} else {
						delayNormalHit(weaponId, attackStyle, getMeleeHit(player, hit1 == 0 ? hit2 : hit2/2), getMeleeHit(player, hit1));
						delayHit(1, weaponId, attackStyle, getMeleeHit(player, hit2/4), getMeleeHit(player, hit1 == 0 ? hit2/2 : hit2/4));
					}
		    	break;
		     case 10887: //anchor
		    	 player.setNextAnimation(new Animation(5870));
				 player.setNextGraphics(new Graphics(1027));
				 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, false, 1.0, true)));
				 break;
		     case 1305: //dragon long
				 player.setNextAnimation(new Animation(12033));
				 player.setNextGraphics(new Graphics(2116));
				 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.25, true)));
				 break;
		     case 3204: //d hally
				 player.setNextAnimation(new Animation(1665));
				 player.setNextGraphics(new Graphics(282));
				 if(target.getSize() < 3)  {//giant npcs wont get stuned cuz of a stupid hit
					 target.setNextGraphics(new Graphics(254, 0, 100));
					 //TODO stun
				 }
				 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.1, true)));
				 if(target.getSize() > 1)
					 delayHit(1, weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.1, true)));
				 break;
		     case 4587: //dragon sci
		    	 player.setNextAnimation(new Animation(12005));
				 player.setNextGraphics(new Graphics(2118));
				 if(target instanceof Player) {
					Player p2 = (Player) target;
				    p2.getPrayer().closeAllPrayers(); //gotta do not disable protect, whatever
				 }
				 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true)));
		    	 break;
		     case 1215: //dragon dagger
		     case 5698: //dds
		    	 player.setNextAnimation(new Animation(1062));
				 player.setNextGraphics(new Graphics(252, 0, 100));
				 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.25, true)));
				 delayHit(1, weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.25, true)));
		    	 break;
		     case 4153: //granite maul
		    	 player.setNextAnimation(new Animation(1667));
				 player.setNextGraphics(new Graphics(340));
				 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.0, true)));
				 combatDelay = 0;
				 break;
		     case 1434: //dragon mace
		    	 player.setNextAnimation(new Animation(1060));
				 player.setNextGraphics(new Graphics(251));
				 delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false, true, 1.45, true)));
				 break;
		    default:
		    	 player.getPackets().sendGameMessage("This weapon has no special Attack, if you still see special bar please relogin.");
				 return combatDelay;
		    }
		    doDefenceEmote();
			return combatDelay;
		}else{
			doDefenceEmote();
			delayNormalHit(weaponId, attackStyle, getMeleeHit(player, getRandomMaxHit(player, weaponId, attackStyle, false)));
			player.setNextAnimation(new Animation(getWeaponAttackEmote(weaponId, attackStyle)));
		}
		return combatDelay;
	}
	
	private int getSpecialAmmount(int weaponId) {
		switch(weaponId) {
		case 4587: //dragon sci
		case 859: //magic longbow
		case 861: //magic shortbow
		case 10284: //Magic composite bow
		case 18332: //Magic longbow (sighted)
			return 55;
	    case 11235: //dark bows
	    case 15701:
	    case 15702:
	    case 15703:
	    case 15704:
			return 65;
		case 10502: //vls
		 case 1305: //dragon long
		 case 1215: //dragon dagger
	     case 5698: //dds
	     case 1434: //dragon mace
			return 25;
		  case 15442:// whip start
		     case 15443:
		     case 15444:
		     case 15441:
		     case 4151: 
		     case 11698: //sgs
		     case 11694: //ags
		     case 13902: //statius hammer
		     case 13905: //vesta spear
		     case 14484: //d claws
		     case 10887: //anchor
		     case 3204: //d hally
		     case 4153: //granite maul
		     case 14684: //zanik cbow
			return 50;
		  case 11730: //ss
		  case 11696: //bgs
		  case 11700: //zgs
			  return 100;
		  case 19784: //korasi sword
			  return 60;
		    	 
		default:
			return 0;
		}
	}
    public int getRandomMaxHit(Player player, int weaponId, int attackStyle, boolean ranging) {
	return getRandomMaxHit(player, weaponId, attackStyle, ranging, true, 1, false);
    }

    public int getRandomMaxHit(Player player, int weaponId, int attackStyle, boolean ranging, boolean defenceAffects, double specMultiplier, boolean usingSpec) {
    	max_hit = getMaxHit(player, weaponId, attackStyle, ranging, usingSpec, specMultiplier);
    	if(defenceAffects) {
        	double att = player.getSkills().getLevel(ranging ? Skills.RANGE : Skills.ATTACK)
        			    + player.getCombatDefinitions().getBonuses()
        			    [ranging ? 4 : CombatDefinitions.getMeleeBonusStyle(weaponId, attackStyle)];
        	att *= ranging ? player.getPrayer().getRangeMultiplier() : player.getPrayer().getAttackMultiplier();
        	double def;
        	if(target instanceof Player) {
        		Player p2 = (Player) target;
        		 def = p2.getSkills().getLevel(Skills.DEFENCE)
        					+ (ranging ? 1.25 : 1.0) * p2.getCombatDefinitions().getBonuses()
        					 [(int) (ranging ? CombatDefinitions.RANGE_DEF : CombatDefinitions.getMeleeDefenceBonus(CombatDefinitions.getMeleeBonusStyle(weaponId, attackStyle)))];
        					def *= p2.getPrayer().getDefenceMultiplier();
        	 }else{
        		 NPC n = (NPC) target;
        		 def = n.getBonuses() == null ? 0 : n.getBonuses()[ranging ? CombatDefinitions.RANGE_DEF : CombatDefinitions.getMeleeDefenceBonus(CombatDefinitions.getMeleeBonusStyle(weaponId, attackStyle))];
        	 }
        	if(usingSpec) {
        		double multiplier = 0.25 + specMultiplier;
        		att *= multiplier;
        	}
    	    double prob = att / def;
    	    if (prob > 0.90) //max, 90% prob hit so even lvl 138 can miss at lvl 3
    		prob = 0.90;
    	    else if (prob < 0.05) //minimun 5% so even lvl 3 can hit lvl 138
    		prob = 0.05;
    	    if(prob < Math.random())
    		return 0;
    	}
    	int hit = Utils.getRandom(max_hit);
    	if(usingSpec) {
    			int halfMaxhit = (int) (max_hit*0.5);
    			double m1 = 0.25+specMultiplier;
    			//if hit gonna be lower than half of max hit and percentage > random, hit = at least half max hit + random
    			if(halfMaxhit > hit && m1 > Math.random()*2)
    				hit = halfMaxhit + Utils.getRandom(halfMaxhit);
    	}
    	return hit;
    }
    
	public static final int getMaxHit(Player player, int weaponId, int attackStyle, boolean ranging, boolean usingSpec, double specMultiplier) {
	       if(!ranging) {
		   int strengthLvl = player.getSkills().getLevel(Skills.STRENGTH); //pot included
		   double xpStyle = CombatDefinitions.getXpStyle(weaponId, attackStyle);
		   double styleBonus = xpStyle == Skills.STRENGTH ? 3 : xpStyle == CombatDefinitions.SHARED ? 1 : 0;
		   double effectiveStrenght = 8+ strengthLvl * player.getPrayer().getStrengthMultiplier() + styleBonus;
		   double strengthBonus = player.getCombatDefinitions().getBonuses()[CombatDefinitions.STRENGTH_BONUS];
		   double baseDamage = 5 + (effectiveStrenght * (1+(strengthBonus/64)));
		   double OtherBonus = 1;
		   if (fullDharokEquipped(player)) {
			   OtherBonus += 1 - (player.getHitpoints()/player.getMaxHitpoints());
		   } 
		   double finaldamage = baseDamage * specMultiplier * OtherBonus;
		   return (int) finaldamage;
	       }else{
	      double rangedLvl = player.getSkills().getLevel(Skills.RANGE); //pot included
		   double styleBonus = attackStyle == 0 ? 3 : attackStyle == 1 ? 0 : 1;
		   double OtherBonus = 1;
		   double voidbonus = 0;
		   if(fullVoidEquipped(player, 11664, 11675)) {
		       voidbonus =  Math.floor(rangedLvl / 5 + 1.6);
		   }
		   double effectiveStrenght = 8+ Math.round(rangedLvl * player.getPrayer().getRangeMultiplier() * OtherBonus)+ styleBonus + voidbonus;
		   double strengthBonus = player.getCombatDefinitions().getBonuses()[CombatDefinitions.RANGED_STR_BONUS];
		   double baseDamage = 5 + effectiveStrenght * (1+(strengthBonus/64));
		   return (int) (baseDamage * specMultiplier);
	       }
	}
	
    public static final boolean fullDharokEquipped(Player player) {
    	int helmId = player.getEquipment().getHatId();
    	int chestId = player.getEquipment().getChestId();
    	int legsId = player.getEquipment().getLegsId();
    	int weaponId = player.getEquipment().getWeaponId();
    	if(helmId == -1 || chestId == -1 || legsId == -1 || weaponId == -1)
    		return false;
    	return ItemDefinitions.getItemDefinitions(helmId).getName().contains("Dharok's")
    			&& ItemDefinitions.getItemDefinitions(chestId).getName().contains("Dharok's")
    			&&ItemDefinitions.getItemDefinitions(legsId).getName().contains("Dharok's")
    			&& ItemDefinitions.getItemDefinitions(weaponId).getName().contains("Dharok's");
    }
	
	 public static final boolean fullVoidEquipped(Player player, int... helmid) {
			if(player.getEquipment().getItems().get(0) == null || player.getEquipment().getItems().get(9) == null || player.getEquipment().getItems().get(4) == null || player.getEquipment().getItems().get(7) == null)
				return false;
			boolean hasHelm = false;
			for(int id : helmid) {
			if(player.getEquipment().getItems().get(0).getId() == id) {
			    hasHelm = true;
			    break;
		    	}
			}
			if(!hasHelm)
			    return false;
			    if ((player.getEquipment().getItems().get(4).getId() == 8839
					    || player.getEquipment().getItems().get(4).getId() == 10611
					    || player.getEquipment().getItems().get(4).getId() == 19785
					    || player.getEquipment().getItems().get(4).getId() == 19787
					    || player.getEquipment().getItems().get(4).getId() == 19789)
				    && (player.getEquipment().getItems().get(7).getId() == 8840
					    || player.getEquipment().getItems().get(7).getId() == 19786
					    || player.getEquipment().getItems().get(7).getId() == 19788
					    || player.getEquipment().getItems().get(7).getId() == 19790)
				    && player.getEquipment().getItems().get(9).getId() == 8842) {
				return true;
			    }
			    return false;
		    }
	
	public void delayNormalHit(int weaponId, int attackStyle, Hit... hits) {
		delayHit(0, weaponId, attackStyle, hits);
	}
    public Hit getMeleeHit(Player player, int damage) {
    	return new Hit(player, damage, HitLook.Melee_Hit);
    }
    
    public Hit getRangeHit(Player player, int damage) {
    	return new Hit(player, damage, HitLook.Range_Hit);
    }
    
    public Hit getMagicHit(Player player, int damage) {
    	return new Hit(player, damage, HitLook.Mage_Hit);
    }
	
	private void delayMagicHit(int delay, final Hit... hits) {
		delayHit(delay, -1, -1, hits);
	}
    
	private void delayHit(int delay, final int weaponId, final int attackStyle, final Hit... hits) {
		addAttackedByDelay(hits[0].getSource());
		WorldTasksManager.schedule(new WorldTask() {
			@Override
			public void run() {
				for(Hit hit : hits) {
					Player player = (Player) hit.getSource();
					if(player.isDead() || player.hasFinished() || target.isDead() || target.hasFinished())
						return;
					target.applyHit(hit); //also reduces damage if needed, pray and special items affect here
					if(hit.getLook() == HitLook.Range_Hit || hit.getLook() == HitLook.Mage_Hit)
					    doDefenceEmote();
					if((hit.getDamage() >= max_hit-5) && (hit.getLook() == HitLook.Mage_Hit || hit.getLook() == HitLook.Range_Hit || hit.getLook() == HitLook.Melee_Hit))
						hit.setCriticalMark();
					if (hit.getLook() == HitLook.Range_Hit || hit.getLook() == HitLook.Melee_Hit) {
						double combatXp = hit.getDamage()/2.5;
						if(combatXp > 0) {
							if(hit.getLook() == HitLook.Range_Hit) {
								if(attackStyle == 2) {
									player.getSkills().addXp(Skills.RANGE/2, combatXp);
									player.getSkills().addXp(Skills.DEFENCE/2, combatXp);
								}else
									player.getSkills().addXp(Skills.RANGE, combatXp);
							
							} else {
								int xpStyle = CombatDefinitions.getXpStyle(weaponId, attackStyle);
								if(xpStyle != CombatDefinitions.SHARED)
									player.getSkills().addXp(xpStyle, combatXp);
								else{
									player.getSkills().addXp(Skills.ATTACK, combatXp/3);
									player.getSkills().addXp(Skills.STRENGTH, combatXp/3);
									player.getSkills().addXp(Skills.DEFENCE, combatXp/3);
								}
							}
							double hpXp = hit.getDamage()/7.5;
							if(hpXp > 0)
								player.getSkills().addXp(Skills.HITPOINTS, hpXp);
						}
					}else if (hit.getLook() == HitLook.Mage_Hit){
						if(hit.getDamage() == 0)
							target.setNextGraphics(new Graphics(85, 0, 100));
						else {
							if(mage_hit_gfx != 0)
								target.setNextGraphics(new Graphics(mage_hit_gfx, 0, 100));
						}
						double combatXp = base_mage_xp * 1 + (hit.getDamage()/5);
						if(combatXp > 0) {
							player.getSkills().addXp(Skills.MAGIC, combatXp);
							double hpXp = hit.getDamage()/7.5;
							if(hpXp > 0)
								player.getSkills().addXp(Skills.HITPOINTS, hpXp);
						}
					}
					if(target instanceof Player) {
						Player p2 = (Player) target;
						if(p2.getCombatDefinitions().isAutoRelatie() && !p2.getSkillExecutor().hasSkillWorking()) {
							p2.closeInterfaces();
							p2.getSkillExecutor().setSkill(new PlayerCombat(hit.getSource()));
						}
					}else {
						@SuppressWarnings("unused")
						NPC n = (NPC) target;
						//TODO make target att me for npcs
					}
					
				}
			}
		}, delay);
	}
	
	private int getWeaponAttackEmote(int weaponId, int attackStyle) {
		if(weaponId != -1) {
			String weaponName = ItemDefinitions.getItemDefinitions(weaponId).getName().toLowerCase();
			if(weaponName != null && !weaponName.equals("null")) {
				if(weaponName.contains("crossbow"))
					return weaponName.contains("karil's crossbow") ? 2075 : 4230;
				if(weaponName.contains("bow"))
					return 426;
				if(weaponName.contains("staff of light")){
					switch(attackStyle) {
					case 0:
						return 15072;
					case 1:
						return 15071;
					case 2:
						return 414;
					}
				}
				if(weaponName.contains("staff"))
					return 419;
				if(weaponName.contains("dart"))
				   return 6600;
				if(weaponName.contains("knife"))
				 return 9055;
				if(weaponName.contains("scimitar") || weaponName.contains("korasi's sword")) {
					switch(attackStyle) {
					case 2:
						return 15072;
					default:
						return 15071;
					}
				}
				if(weaponName.contains("mace")) {
					switch(attackStyle) {
					case 2:
						return 400;
					default:
						return 401;
					}
				}
				if(weaponName.contains("hatchet")) {
					switch(attackStyle) {
					case 2:
						return 401;
					default:
						return 395;
					}
				}
				if(weaponName.contains("warhammer")) {
					switch(attackStyle) {
					default:
						return 401;
					}
				}
				if(weaponName.contains("claws")) {
					switch(attackStyle) {
					case 2:
						return 1067;
					default:
						return 393;
					}
				}
				if(weaponName.contains("whip")) {
					switch(attackStyle) {
					case 1:
						return 11969;
					case 2:
						return 11970;
					default:
						return 11968;
					}
				}
				if(weaponName.contains("anchor")) {
					switch(attackStyle) {
					default:
					return 5865;
				}
			}
				if(weaponName.contains("tzhaar-ket-em")) {
					switch(attackStyle) {
					default:
					return 401;
				}
			}
				if(weaponName.contains("tzhaar-ket-om")) {
					switch(attackStyle) {
					default:
					return 13691;
				}
			}
				if(weaponName.contains("halberd")) {
					switch(attackStyle) {
					case 1:
						return 440;
					default:
						return 428;
					}
				}
				if(weaponName.contains("zamorakian spear")) {
					switch(attackStyle) {
					case 1:
						return 12005;
					case 2:
					return 12009;
					default:
						return 12006;
					}
				}
				if(weaponName.contains("spear")) {
					switch(attackStyle) {
					case 1:
						return 440;
					case 2:
						return 429;
					default:
						return 428;
					}
				}
				if(weaponName.contains("pickaxe")) {
					switch(attackStyle) {
					case 2:
						return 400;
					default:
						return 401;
					}
				}
				if(weaponName.contains("dagger")) {
					switch(attackStyle) {
					case 2:
						return 377;
					default:
						return 376;
					}
				}
				if(weaponName.contains("longsword")) {
					switch(attackStyle) {
					case 2:
						return 12310;
					default:
						return 12311;
					}
				}
				if(weaponName.contains("rapier")) {
					switch(attackStyle) {
					case 2:
						return 13048;
					default:
						return 13049;
					}
				}
				
				if(weaponName.contains("godsword")) {
					switch(attackStyle) {
					case 2:
						return 11980;
					case 3:
						return 11981;
					default:
						return 11979;
					}
				}
				if(weaponName.contains("greataxe")) {
					switch(attackStyle) {
					case 2:
						return 12003;
						default:
							return 12002;
					}
				}
				if(weaponName.contains("granite maul")) {
					switch(attackStyle) {
						default:
							return 1665;
					}
				}
				if(weaponName.contains("2h sword") || weaponName.equals("saradomin sword")) {
					switch(attackStyle) {
					case 2:
						return 7048;
					case 3:
						return 7049;
					default:
						return 7041;
					}
				}
					
			}
		}
		switch(weaponId) {
		case 16405://novite maul
		case 16407://Bathus maul
		case 16409://Maramaros maul
		case 16411://Kratonite maul
		case 16413://Fractite maul
		case 18353://chaotic maul
		case 16415://Zephyrium maul
		case 16417://Argonite maul
		case 16419://Katagon maul
		case 16421://Gorgonite maul
		case 16423://Promethium maul
		case 16425://primal maul
			return 2661; //maul
		case 13883: //morrigan thrown axe
    	    return 10504;
		case 15241:
			return 12174;
		default:
			switch(attackStyle) {
			case 1:
				return 423;
			default:
				return 422; //todo default emote
			}
		}
	}
	
	private void doDefenceEmote() {
		if(target.getNextAnimation() != null)  //if has att emote already
			return;
		target.setNextAnimation(new Animation(getDefenceEmote()));
	}
	
	private int getDefenceEmote() {
		if(target instanceof NPC) {
			NPC n = (NPC) target;
			return n.getDefenceEmote();
		}else{
			Player p = (Player) target;
			int shieldId = p.getEquipment().getShieldId();
			if(shieldId == -1) {
				int weaponId = p.getEquipment().getWeaponId();
				if(weaponId == -1)
					return 424;
				String weaponName = ItemDefinitions.getItemDefinitions(weaponId).getName().toLowerCase();
				if(weaponName != null && !weaponName.equals("null")) {
					if(weaponName.contains("scimitar") || weaponName.contains("korasi sword"))
						return 15074;
					if(weaponName.contains("whip"))
						return 11974;
					if(weaponName.contains("longsword"))
						return 388;
					if(weaponName.contains("dagger"))
						return 378;
					if(weaponName.contains("rapier"))
						return 13038;
					if (weaponName.contains("staff of light"))
						return 12806;
					if(weaponName.contains("staff"))
						return 420;
					if(weaponName.contains("pickaxe"))
						return 397;
					if(weaponName.contains("mace"))
						return 401;
					if(weaponName.contains("hatchet"))
						return 397;
					if(weaponName.contains("greataxe"))
						return 12004;
					if(weaponName.contains("warhammer") || weaponName.contains("tzhaar-ket-em"))
						return 403;
					if(weaponName.contains("maul") || weaponName.contains("tzhaar-ket-om"))
						return 1666;
					if(weaponName.contains("zamorakian spear"))
						return 12008;
					if(weaponName.contains("spear") || weaponName.contains("halberd") || weaponName.contains("hasta"))
						return 430;
					if(weaponName.contains("2h sword") || weaponName.contains("godsword") || weaponName.equals("saradomin sword"))
						return 7050;
				}
				return 424;
			}
			String shieldName = ItemDefinitions.getItemDefinitions(shieldId).getName().toLowerCase();
			if(shieldName != null && !shieldName.equals("null")) {
				if(shieldName.contains("shield"))
					return 1156;
				if(shieldName.contains("defender"))
					return 4177;
			}
			switch(shieldId) {
			case -1:
			default:
				return 424;
			}
		}
			
		
	}
	
	private int getMeleeCombatDelay(int weaponId) {
		if(weaponId != -1) {
			String weaponName = ItemDefinitions.getItemDefinitions(weaponId).getName().toLowerCase();
			//Interval 2.4
			if(weaponName.contains("zamorakian spear"))//Works dont edit this ^^
				return 4;
			//Interval 3.0
			if(weaponName.contains("spear") || 
					weaponName.contains("longsword") || 
					weaponName.contains("hatchet") || 
					weaponName.contains("pickaxe") || 
					weaponName.contains("mace") || 
					weaponName.contains("hasta") || 
					weaponName.contains("warspear") || 
					weaponName.contains("flail") || 
					weaponName.contains("hammers"))
				return 5;
			//Interval 3.6
			if(weaponName.contains("godsword") || 
					weaponName.contains("warhammer") || 
					weaponName.contains("battleaxe"))
				return 6;
			//Interval 4.2
			if(weaponName.contains("greataxe") || 
					weaponName.contains("halberd") || 
					weaponName.contains("2h sword") || 
					weaponName.contains("maul") || 
					weaponName.contains("two handed sword"))
				return 7;
		}
		switch(weaponId) {	
		case 6527://tzhaar-ket-em
			return 5;
		case 10887://barrelchest anchor
			return 6;
		case 15403://balmung
		case 6528://tzhaar-ket-om
			return 7;
		default:
			return 4;
		}
	}

	private void addAttackedByDelay(Entity player) {
		target.setAttackedBy(player);
		target.setAttackedByDelay(System.currentTimeMillis()+8000); //8seconds
	}
	
	@Override
	public void stop(Player player) {
		player.setNextFaceEntity(null);
	}
	
	private boolean checkAll(Player player) {
		if(player.isDead() || player.hasFinished() || target.isDead() || target.hasFinished())
			return false;
		int distanceX = player.getX()-target.getX();
		int distanceY = player.getY()-target.getY();
		int size = target.getSize();
		int maxDistance = 16;
		if(player.getPlane() != target.getPlane() || distanceX > size+maxDistance || distanceX < -1-maxDistance || distanceY > size+maxDistance || distanceY < -1-maxDistance)
			return false;
		if(player.getFreezeDelay() >= System.currentTimeMillis())
			return true;
		if(target instanceof Player) {
			Player p2 = (Player) target;
			if(!player.isCanPvp() || !p2.isCanPvp())  //cant pvp, no message needed as sent when u click
				return false;
		}
		if(!target.isAtMultiArea() || ! player.isAtMultiArea()) {
			if(player.getAttackedBy() != target && player.getAttackedByDelay() > System.currentTimeMillis())
				return false;
			if(target.getAttackedBy() != player && target.getAttackedByDelay() > System.currentTimeMillis())
				return false;
		}
		int isRanging = isRanging(player);
		maxDistance = isRanging != 0 || player.getCombatDefinitions().getSpellId() > 0 ? 7 : 0;
		if(distanceX > size+maxDistance || distanceX < -1-maxDistance || distanceY > size+maxDistance || distanceY < -1-maxDistance) {
			if(!player.hasWalkSteps())
				player.addWalkStepsInteract(target.getX(), target.getY(), 2, size, true);
			return true;
		}else {
			player.resetWalkSteps();
		}
		if(player.getX() == target.getX() && player.getY() == target.getY()) {
			if(!player.addWalkSteps(target.getX()+1, target.getY(), 1))
				if(!player.addWalkSteps(target.getX()-1, target.getY(), 1))
					if(!player.addWalkSteps(target.getX(), target.getY()+1, 1))
						if(!player.addWalkSteps(target.getX(), target.getY()-1, 1))
							return false;
		}
		return true;
	}
	
	   /*
     * 0 not ranging, 1 invalid ammo so stops att, 2 can range, 3 no ammo
     */
	public static final int isRanging(Player player) {
    int weaponId = player.getEquipment().getWeaponId();
	if (weaponId == -1)
	    return 0;
	    String name = ItemDefinitions.getItemDefinitions(weaponId).getName();
	    if(name != null) { //those dont need arrows
		if(name.contains("knife")
			|| name.contains("dart")
			|| name.contains("javelin")
			|| name.contains("thrownaxe")
			|| name.contains("throwing axe")
			|| name.contains("Crystal bow")
			|| name.equalsIgnoreCase("Zaryte bow"))
		    return 2;
	}
	int ammoId = player.getEquipment().getAmmoId();
	switch(weaponId) {
	case 15241: // Hand cannon
	    switch(ammoId) {
	    case -1:
		return 3;
	    case 15243: //bronze arrow
	    return 2;
	    default:
		return 1;
	    }
	case 839: //longbow
	case 841: //shortbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 882: //bronze arrow
	    case 884: //iron arrow
	    return 2;
	    default:
		return 1;
	    }
	case 843: //oak longbow
	case 845: //oak shortbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 882: //bronze arrow
	    case 884: //iron arrow
	    case 886: //steel arrow
	    return 2;
	    default:
		return 1;
	    }
	case 847: //willow longbow
	case 849: //willow shortbow
	case 13541: //Willow composite bow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 882: //bronze arrow
	    case 884: //iron arrow
	    case 886: //steel arrow
	    case 888: //mithril arrow
	    return 2;
	    default:
		return 1;
	    }
	case 851: //maple longbow
	case 853: //maple shortbow
	case 18331: //Maple longbow (sighted)
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 882: //bronze arrow
	    case 884: //iron arrow
	    case 886: //steel arrow
	    case 888: //mithril arrow
	    case 890: //adamant arrow
	    return 2;
	    default:
		return 1;
	    }
	case 2883://ogre bow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 2866: //ogre arrow
	    return 2;
	    default:
		return 1;
	    }
	case 4827://Comp ogre bow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 2866: //ogre arrow
	    case 4773: //bronze brutal
	    case 4778: //iron brutal
	    case 4783: //steel brutal
	    case 4788: //black brutal
	    case 4793: //mithril brutal
	    case 4798: //adamant brutal
	    case 4803: //rune brutal
	    return 2;
	    default:
		return 1;
	    }
	case 855: //yew longbow
	case 857: //yew shortbow
	case 10281: //Yew composite bow
	case 14121: //Sacred clay bow
	case 859: //magic longbow
	case 861: //magic shortbow
	case 10284: //Magic composite bow
	case 18332: //Magic longbow (sighted)
	case 6724: //seercull
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 882: //bronze arrow
	    case 884: //iron arrow
	    case 886: //steel arrow
	    case 888: //mithril arrow
	    case 890: //adamant arrow
	    case 892: //rune arrow
	    return 2;
	    default:
		return 1;
	    }
	case 11235: //dark bows
	case 15701:
	case 15702:
	case 15703:
	case 15704:
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 882: //bronze arrow
	    case 884: //iron arrow
	    case 886: //steel arrow
	    case 888: //mithril arrow
	    case 890: //adamant arrow
	    case 892: //rune arrow
	    case 11212: //dragon arrow
	    return 2;
	    default:
		return 1;
	    }
	case 19143: //saradomin bow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 19152: //saradomin arrow
	    return 2;
	    default:
		return 1;
	    }
	case 19146: //guthix bow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 19157: //guthix arrow
	    return 2;
	    default:
		return 1;
	    }
	case 19149: //zamorak bow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 19162: //zamorak arrow
	    return 2;
	    default:
		return 1;
	    }
	case 4734: //karil crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 4740: //bolt rack
	    return 2;
	    default:
		return 1;
	    }
	case 10156: //hunters crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 10158: //Kebbit bolts
	    case 10159: //Long kebbit bolts
	    return 2;
	    default:
		return 1;
	    }
	case 8880: //Dorgeshuun c'bow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 8882: //bone bolts
	    return 2;
	    default:
		return 1;
	    }
	case 14684: //zanik crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 9141: //steel bolts
	    case 13083: //black bolts
	    case 9142:// mithril bolts
	    case 9143: //adam bolts
	    case 9145: //silver bolts
	    case 8882: //bone bolts
	    return 2;
	    default:
		return 1;
	    }
	case 767: //phoenix crossbow
	case 837: //crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    return 2;
	    default:
		return 1;
	    }    
	case 9174: //bronze crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9236: //Opal bolts (e)
	    return 2;
	    default:
		return 1;
	    } 
	case 9176: //blurite crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 9141: //steel bolts
	    case 13083: //black bolts
	    case 9236: //Opal bolts (e)
	    case 9238: //Pearl bolts (e)
	    case 9239: //Topaz bolts (e)
	    case 9139: //Blurite bolts
	    case 9237: //Jade bolts (e)
	    return 2;
	    default:
		return 1;
	    } 
	case 9177: //iron crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 9236: //Opal bolts (e)
	    case 9238: //Pearl bolts (e)
	    return 2;
	    default:
		return 1;
	    } 
	case 9179: //steel crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 9141: //steel bolts
	    case 9236: //Opal bolts (e)
	    case 9238: //Pearl bolts (e)
	    case 9239: //Topaz bolts (e)
	    return 2;
	    default:
		return 1;
	    }  
	case 13081: //black crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 9141: //steel bolts
	    case 13083: //black bolts
	    case 9236: //Opal bolts (e)
	    case 9238: //Pearl bolts (e)
	    case 9239: //Topaz bolts (e)
	    return 2;
	    default:
		return 1;
	    }  
	case 9181: //Mith crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 9141: //steel bolts
	    case 13083: //black bolts
	    case 9142:// mithril bolts
	    case 9145: //silver bolts
	    case 9236: //Opal bolts (e)
	    case 9238: //Pearl bolts (e)
	    case 9239: //Topaz bolts (e)
	    case 9240: //Sapphire bolts (e)
	    case 9241: //Emerald bolts (e)
	    return 2;
	    default:
		return 1;
	    }  
	case 9183: //adam c bow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 9141: //steel bolts
	    case 13083: //black bolts
	    case 9142:// mithril bolts
	    case 9143: //adam bolts
	    case 9145: //silver bolts wtf
	    case 9236: //Opal bolts (e)
	    case 9238: //Pearl bolts (e)
	    case 9239: //Topaz bolts (e)
	    case 9240: //Sapphire bolts (e)
	    case 9241: //Emerald bolts (e)
	    case 9242: //Ruby bolts (e)
	    case 9243: //Diamond bolts (e)
	    return 2;
	    default:
		return 1;
	    }
	case 9185: //rune c bow
	case 18357: //chaotic crossbow
	    switch(ammoId) {
	    case -1:
			return 3;
	    case 877: //bronze bolts
	    case 9140: //iron bolts
	    case 9141: //steel bolts
	    case 13083: //black bolts
	    case 9142:// mithril bolts
	    case 9143: //adam bolts
	    case 9144: //rune bolts
	    case 9145: //silver bolts wtf
	    case 9236: //Opal bolts (e)
	    case 9238: //Pearl bolts (e)
	    case 9239: //Topaz bolts (e)
	    case 9240: //Sapphire bolts (e)
	    case 9241: //Emerald bolts (e)
	    case 9242: //Ruby bolts (e)
	    case 9243: //Diamond bolts (e)
	    case 9244: //Dragon bolts (e)
	    case 9245: //Onyx bolts (e)
	    return 2;
	    default:
		return 1;
	    }
	default:
	return 0;
	}
    }
    
}
